package net.goutalk.glcs.common.interceptor;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import net.goutalk.glcs.common.utils.RedisUtil;
import net.goutalk.glcs.module.authority.utils.AuthorityUtil;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Setter;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.select.*;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.util.List;


/**
 * 数据权限处理器
 *
 * @author tanyujie
 * @Date: 2023/2/21 16:11
 * @since 3.4.1 +
 */
@Data
@EqualsAndHashCode(callSuper = true)
public class DataScopeInnerInterceptor extends JsqlParserSupport implements InnerInterceptor {

//    private DataPermissionHandler dataPermissionHandler;

    @Setter
    private static RedisUtil redisUtil;


    @Override
    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) return;
        PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);
        mpBs.sql(parserSingle(mpBs.sql(), ms.getId()));
    }

    @Override
    protected void processSelect(Select select, int index, String sql, Object obj) {
        SelectBody selectBody = select.getSelectBody();
        if (selectBody instanceof PlainSelect) {
            this.setWhere((PlainSelect) selectBody, (String) obj);
        } else if (selectBody instanceof SetOperationList) {
            SetOperationList setOperationList = (SetOperationList) selectBody;
            List<SelectBody> selectBodyList = setOperationList.getSelects();
            selectBodyList.forEach(s -> this.setWhere((PlainSelect) s, (String) obj));
        }
    }

    /**
     * 设置 where 条件
     *
     * @param plainSelect  查询对象
     * @param whereSegment 查询条件片段
     */

    protected void setWhere(PlainSelect plainSelect, String whereSegment) {
        //有可能是没有登录的非web请求（定时任务，初始运行） 所以必须要try catch一下
        try {
            //首先必须要登录 才需要判断数据权限的问题
            if (!StpUtil.isLogin()) {
                return;
            }
        } catch (Exception ignored) {
            return;
        }


        FromItem fromItem = plainSelect.getFromItem();
        Table fromTable = (Table) fromItem;

        String alias = null;
        if (ObjectUtil.isNotNull(fromTable.getAlias())) {
            alias = fromTable.getAlias().getName();
        }

        Expression dataAuthExpression = AuthorityUtil.getDataAuthExpressionByTableName(fromTable.getName(), alias);

        Expression currentExpression = plainSelect.getWhere();
        if (ObjectUtil.isNotNull(dataAuthExpression)) {
            if(currentExpression == null){
                currentExpression = dataAuthExpression;
            }
            else {
                currentExpression = new AndExpression(currentExpression, dataAuthExpression);
            }
            plainSelect.setWhere(currentExpression);
        }
    }

}